package 反射.代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
//public class 代理3 {
//
//}
//一、概述
//1. 什么是代理
//   我们大家都知道微商代理，简单地说就是代替厂家卖商品，厂家“委托”代理为其销售商品。关于微商代理，首先我们从他们那里买东西时通常不知道背后的厂家究竟
//   是谁，也就是说，“委托者”对我们来说是不可见的；其次，微商代理主要以朋友圈的人为目标客户，这就相当于为厂家做了一次对客户群体的“过滤”。我们把微商
//   代理和厂家进一步抽象，前者可抽象为代理类，后者可抽象为委托类（被代理类）。通过使用代理，通常有两个优点，并且能够分别与我们提到的微商代理的两个
//   特点对应起来：
//
//优点一：可以隐藏委托类的实现；
//优点二：可以实现客户与委托类间的解耦，在不修改委托类代码的情况下能够做一些额外的处理。
// 
//2. 静态代理
//   若代理类在程序运行前就已经存在，那么这种代理方式被成为静态代理，这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下，静态代理中的
//   代理类和委托类会实现同一接口或是派生自相同的父类。下面我们用Vendor类代表生产厂家，BusinessAgent类代表微商代理，来介绍下静态代理的简单
//   实现，委托类和代理类都实现了Sell接口，Sell接口的定义如下：

interface Sell {
    void sell(String x);
    void ad(Integer y);
    void hello();
}
 
//Vendor类的定义如下：

//class Vendor implements Sell {
//    public void sell() {
//        System.out.println("In sell method");
//    }
//    public void ad() {
//        System,out.println("ad method")
//    }
//}

//代理类BusinessAgent的定义如下：

//class BusinessAgent implements Sell {
//     private Vendor mVendor;
//   
//     public BusinessAgent(Vendor vendor) {
//         mVendor = vendor;
//     }
//    
//     public void sell() { mVendor.sell(); }
//     public void ad() { mVendor.ad(); }
// }
//
//从BusinessAgent类的定义我们可以了解到，静态代理可以通过聚合来实现，让代理类持有一个委托类的引用即可。
//
//    下面我们考虑一下这个需求：给Vendor类增加一个过滤功能，只卖货给大学生。通过静态代理，我们无需修改Vendor类的代码就可以实现，
//    只需在BusinessAgent类中的sell方法中添加一个判断即可如下所示：
//
//public class BusinessAgent implements Sell {
//    ...
//    public void sell() {
//        if (isCollegeStudent()) {
//            vendor.sell();
//        }
//    }
//    ...
//}

//    这对应着我们上面提到的使用代理的第二个优点：可以实现客户与委托类间的解耦，在不修改委托类代码的情况下能够做一些额外的处理。静态代理的局限在于运
//    行前必须编写好代理类，下面我们重点来介绍下运行时生成代理类的动态代理方式。
//
// 
//
//二、动态代理
//1. 什么是动态代理
//    代理类在程序运行时创建的代理方式被成为动态代理。也就是说，这种情况下，代理类并不是在Java代码中定义的，而是在运行时根据我们在Java代码中
//    的“指示”动态生成的。相比于静态代理，动态代理的优势在于可以很方便的对代理类的函数进行统一的处理，而不用修改每个代理类的函数。这么说比较抽象，
//    下面我们结合一个实例来介绍一下动态代理的这个优势是怎么体现的。
//
//    现在，假设我们要实现这样一个需求：在执行委托类中的方法之前输出“before”，在执行完毕后输出“after”。我们还是以上面例子中的Vendor类作为
//    委托类，BusinessAgent类作为代理类来进行介绍。首先我们来使用静态代理来实现这一需求，相关代码如下：
//
//public class BusinessAgent implements Sell {
//    private Vendor mVendor;
//    
//    public BusinessAgent(Vendor vendor) {
//        this.mVendor = vendor;
//    }
//
//    public void sell() {
//        System.out.println("before");
//        mVendor.sell();
//        System.out.println("after");
//    }
//
//    public void ad() {
//        System.out.println("before");
//        mVendor.ad();
//        System.out.println("after");
//    }
//}
//
//     从以上代码中我们可以了解到，通过静态代理实现我们的需求需要我们在每个方法中都添加相应的逻辑，这里只存在两个方法所以工作量还不算大，
//     假如Sell接口中包含上百个方法呢？这时候使用静态代理就会编写许多冗余代码。通过使用动态代理，我们可以做一个“统一指示”，从而对所有代理类的方
//     法进行统一处理，而不用逐一修改每个方法。下面我们来具体介绍下如何使用动态代理方式实现我们的需求。

//2. 使用动态代理
//（1）InvocationHandler接口
//    在使用动态代理时，我们需要定义一个位于代理类与委托类之间的中介类，这个中介类被要求实现InvocationHandler接口，这个接口的定义如下：
//
//public interface InvocationHandler {
//    Object invoke(Object proxy, Method method, Object[] args);
//}
//    从InvocationHandler这个名称我们就可以知道，实现了这个接口的中介类用做“调用处理器”。当我们调用代理类对象的方法时，这个“调用”会转
//    送到invoke方法中，代理类对象作为proxy参数传入，参数method标识了我们具体调用的是代理类的哪个方法，args为这个方法的参数。这样一来，
//    我们对代理类中的所有方法的调用都会变为对invoke的调用，这样我们可以在invoke方法中添加统一的处理逻辑（也可以根据method参数对不同的
//    代理类方法做不同的处理）。因此我们只需在中介类的invoke方法实现中输出“before”，然后调用委托类的invoke方法，再输出“after”。下面
//    我们来一步一步具体实现它。
//
// 
//（2）委托类的定义
//    动态代理方式下，要求委托类必须实现某个接口，这里我们实现的是Sell接口。委托类Vendor类的定义如下：

class Vendor implements Sell {
    public void sell(String x) {
        System.out.println("In sell method "+x);
    }
    public void ad(Integer y) {
        System.out.println("ad method "+y);
        
    }
    public void hello() {
    	System.out.println("hello method");
    }
}
 
//（3）中介类
//    上面我们提到过，中介类必须实现InvocationHandler接口，作为调用处理器”拦截“对代理类方法的调用。中介类的定义如下：

//public 
class DynamicProxy implements InvocationHandler {
    private Object obj; //obj为委托类对象；
    
    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before:"+method+Arrays.toString(args));
        Object result = method.invoke(obj, args);
        System.out.println("after");
        return result;
    }
}
//
//     从以上代码中我们可以看到，中介类持有一个委托类对象引用，在invoke方法中调用了委托类对象的相应
//     方法（Object result = method.invoke(obj, args);),看到这里是不是觉得似曾相识？
//     通过聚合方式持有委托类对象引用，把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗？实际上，
//     中介类与委托类构成了静态代理关系，在这个关系中，中介类是代理类，委托类就是委托类；
//
//代理类与中介类也构成一个静态代理关系，在这个关系中，中介类是委托类，代理类是代理类。也就是说，动态代理关系由两组静态代理关系组成，
//这就是动态代理的原理。下面我们来介绍一下如何”指示“以动态生成代理类。
//
//（4）动态生成代理类
//    动态生成代理类的相关代码如下：

public class 代理1 {
    public static void main(String[] args) {
        //创建中介类实例
        DynamicProxy  inter = new DynamicProxy(new Vendor());
        //加上这句将会产生一个$Proxy0.class文件，这个文件即为动态生成的代理类文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 
        //获取代理类实例sell
        Sell sell = (Sell) Proxy.newProxyInstance(Sell.class.getClassLoader(),
        new Class[] {Sell.class}, inter);
        //通过代理类对象调用代理类方法，实际上会转到invoke方法调用
        sell.sell("x");
        sell.ad(22);
        sell.hello();
    }
}

//    在以上代码中，我们调用Proxy类的newProxyInstance方法来获取一个代理类实例。这个代理类实现了我们指定的接口并且会把方法调用分发到指定的
//    调用处理器。这个方法的声明如下：
//
//public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
//    方法的三个参数含义分别如下：
//1.loader：定义了代理类的ClassLoder；
//2.interfaces：代理类实现的接口列表
//3.h：调用处理器，也就是我们上面定义的实现了InvocationHandler接口的类实例
//    我们运行一下，看看我们的动态代理是否能正常工作。我这里运行后的输出为：
//        说明我们的动态代理确实奏效了。
//   
//    上面我们已经简单提到过动态代理的原理，这里再简单的总结下：首先通过newProxyInstance方法获取代理类实例，而后我们便可以通过这个代理类实例
//调用代理类的方法，对代理类的方法的调用实际上都会调用中介类（调用处理器）的invoke方法，在invoke方法中我们调用委托类的相应方法，并且可以添加自己
//的处理逻辑。下面我们来看一下生成的代理类的代码究竟是怎样的。
//    
//3. 动态代理类的源码分析
//    通过运行Main，我们会得到一个名为“$Proxy”的class文件，这个文件即为动态生成的代理类，我们通过反编译来查看下这个代理类的源代码：

//package com.sun.proxy;
//
//import java.lang.reflect.InvocationHandler;
//import java.lang.reflect.Method;
//import java.lang.reflect.Proxy;
//import java.lang.reflect.UndeclaredThrowableException;
//
//public final class $Proxy0 extends Proxy implements Sell {
//    //这5个Method对象分别代表equals()、toString()、ad()、sell()、hashCode()方法
//    private static Method m1;
//    private static Method m2;
//    private static Method m4;
//    private static Method m3;
//    private static Method m0;
//    
//    //构造方法接收一个InvocationHandler对象为参数，这个对象就是代理类的“直接委托类”（真正的委托类可以看做代理类的“间接委托类”）
//    public $Proxy0(InvocationHandler var1) throws  {
//        super（var1);
//    }
//
//    //对equals方法的调用实际上转为对super.h.invoke方法的调用，父类中的h即为我们在构造方法中传入的InvocationHandler对象，
//以下的toString()、sell()、ad()、hashCode()等方法同理
//    public final boolean equals(Object var1) throws  {
//        try {
//            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();
//        } catch (RuntimeException | Error var3) {
//            throw var3;
//        } catch (Throwable var4) {
//            throw new UndeclaredThrowableException(var4);
//        }
//    }
//
//    public final String toString() throws  {
//        try {
//            return (String)super.h.invoke(this, m2, (Object[])null);
//        } catch (RuntimeException | Error var2) {
//            throw var2;
//        } catch (Throwable var3) {
//            throw new UndeclaredThrowableException(var3);
//        }
//    }
//
//    public final void ad() throws  {
//        try {
//            super.h.invoke(this, m4, (Object[])null);
//        } catch (RuntimeException | Error var2) {
//            throw var2;
//        } catch (Throwable var3) {
//            throw new UndeclaredThrowableException(var3);
//        }
//    }
//
//    public final void sell() throws  {
//        try {
//            super.h.invoke(this, m3, (Object[])null);
//        } catch (RuntimeException | Error var2) {
//            throw var2;
//        } catch (Throwable var3) {
//            throw new UndeclaredThrowableException(var3);
//        }
//    }
//
//    public final int hashCode() throws  {
//        try {
//            return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
//        } catch (RuntimeException | Error var2) {
//            throw var2;
//        } catch (Throwable var3) {
//            throw new UndeclaredThrowableException(var3);
//        }
//    }
//    
//    //这里完成Method对象的初始化（通过反射在运行时获得Method对象）
//    static {
//        try {
//            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
//            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
//            m4 = Class.forName("Sell").getMethod("ad", new Class[0]);
//            m3 = Class.forName("Sell").getMethod("sell", new Class[0]);
//            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
//        } catch (NoSuchMethodException var2) {
//            throw new NoSuchMethodError(var2.getMessage());
//        } catch (ClassNotFoundException var3) {
//            throw new NoClassDefFoundError(var3.getMessage());
//        }
//    }
//}

//我们可以看到，以上代码的逻辑十分简单，我们在注释中也做出了相关的说明。（以上代码中涉及到反射的使用，对于反射还不是很熟悉的小伙伴可以
//参考这里：Java核心技术点之反射）
//
//    现在，我们已经了解了动态代理的使用，也搞清楚了它的实现原理，更进一步的话我们可以去了解动态代理类的生成过程，只需要去
//阅读newProxyInstance方法的源码即可，这个方法的逻辑也没有复杂的地方，这里就不展开了。大家可以参考这篇文章：公共技术点之动态代理
//
//
//公共技术点之动态代理
//1. 相关概念
//1.1 代理
//在某些情况下，我们不希望或是不能直接访问对象 A，而是通过访问一个中介对象 B，由 B 去访问 A 达成目的，这种方式我们就称为代理。
//这里对象 A 所属类我们称为委托类，也称为被代理类，对象 B 所属类称为代理类。
//代理优点有：
//
//隐藏委托类的实现
//解耦，不改变委托类代码情况下做一些额外处理，比如添加初始判断及其他公共操作
//根据程序运行前代理类是否已经存在，可以将代理分为静态代理和动态代理。
//
//1.2 静态代理
//代理类在程序运行前已经存在的代理方式称为静态代理。
//通过上面解释可以知道，由开发人员编写或是编译器生成代理类的方式都属于静态代理，如下是简单的静态代理实例：
//
//class ClassA {
//    public void operateMethod1() {};
//
//    public void operateMethod2() {};
//
//    public void operateMethod3() {};
//}
//
//public class ClassB {
//    private ClassA a;
//
//    public ClassB(ClassA a) {
//        this.a = a;
//    }
//
//    public void operateMethod1() {
//        a.operateMethod1();
//    };
//
//    public void operateMethod2() {
//        a.operateMethod2();
//    };
//
//    // not export operateMethod3()
//}
//
// 
//上面ClassA是委托类，ClassB是代理类，ClassB中的函数都是直接调用ClassA相应函数，并且隐藏了Class的operateMethod3()函数。
//
//静态代理中代理类和委托类也常常继承同一父类或实现同一接口。
//
//1.3 动态代理
//代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。
//
//Java 提供了动态代理的实现方式，可以在运行时刻动态生成代理类。这种代理方式的一大好处是可以方便对代理类的函数做统一或特殊处理，如记录所有函数执行
//时间、所有函数执行前添加验证判断、对某个特殊函数进行特殊操作，而不用像静态代理方式那样需要修改每个函数。
//
//静态代理比较简单，本文上面已简单介绍，下面重点介绍动态代理。
//
//2. 动态代理实例
//实现动态代理包括三步：
//(1). 新建委托类；
//(2). 实现InvocationHandler接口，这是负责连接代理类和委托类的中间类必须实现的接口；
//(3). 通过Proxy类新建代理类对象。
//
//下面通过实例具体介绍，假如现在我们想统计某个类所有函数的执行时间，传统的方式是在类的每个函数前打点统计，动态代理方式如下：
//
//2.1 新建委托类
//public interface Operate {
//
//    public void operateMethod1();
//
//    public void operateMethod2();
//
//    public void operateMethod3();
//}
//
//public class OperateImpl implements Operate {
//
//    @Override
//    public void operateMethod1() {
//        System.out.println("Invoke operateMethod1");
//        sleep(110);
//    }
//
//    @Override
//    public void operateMethod2() {
//        System.out.println("Invoke operateMethod2");
//        sleep(120);
//    }
//
//    @Override
//    public void operateMethod3() {
//        System.out.println("Invoke operateMethod3");
//        sleep(130);
//    }
//
//    private static void sleep(long millSeconds) {
//        try {
//            Thread.sleep(millSeconds);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//    }
//}
//Operate是一个接口，定了了一些函数，我们要统计这些函数的执行时间。
//OperateImpl是委托类，实现Operate接口。每个函数简单输出字符串，并等待一段时间。
//动态代理要求委托类必须实现了某个接口，比如这里委托类OperateImpl实现了Operate，原因会后续在微博公布。
//
//2.2. 实现 InvocationHandler 接口
//public class TimingInvocationHandler implements InvocationHandler {
//
//    private Object target;
//
//    public TimingInvocationHandler() {}
//
//    public TimingInvocationHandler(Object target) {
//        this.target = target;
//    }
//
//    @Override
//    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        long start = System.currentTimeMillis();
//        Object obj = method.invoke(target, args);
//        System.out.println(method.getName() + " cost time is:" + (System.currentTimeMillis() - start));
//        return obj;
//    }
//}
//target属性表示委托类对象。
//
//InvocationHandler是负责连接代理类和委托类的中间类必须实现的接口。其中只有一个
//
//public Object invoke(Object proxy, Method method, Object[] args)函数需要去实现
//参数：
// -proxy表示下面2.3 通过 Proxy.newProxyInstance() 生成的代理类对象。
// -method表示代理对象被调用的函数。
// -args表示代理对象被调用的函数的参数。
// 
//调用代理对象的每个函数实际最终都是调用了InvocationHandler的invoke函数。这里我们在invoke实现中添加了开始结束计时，其中还调用了委托类
//对象target的相应函数，这样便完成了统计执行时间的需求。
//invoke函数中我们也可以通过对method做一些判断，从而对某些函数特殊处理。
//
//2.3. 通过 Proxy 类静态函数生成代理对象
//public class 代理3 {
//    public static void main(String[] args) {
//        // create proxy instance
//        TimingInvocationHandler timingInvocationHandler = new TimingInvocationHandler(new OperateImpl());
//        Operate operate = (Operate)(Proxy.newProxyInstance(Operate.class.getClassLoader(), 
//			new Class[] {Operate.class},
//          timingInvocationHandler));
//
//        // call method of proxy instance
//        operate.operateMethod1();
//        System.out.println();
//        operate.operateMethod2();
//        System.out.println();
//        operate.operateMethod3();
//    }
//}
//这里我们先将委托类对象new OperateImpl()作为TimingInvocationHandler构造函数入参创建timingInvocationHandler对象；
//然后通过Proxy.newProxyInstance(…)函数新建了一个代理对象，实际代理类就是在这时候动态生成的。我们调用该代理对象的函数就会调用
//到timingInvocationHandler的invoke函数(是不是有点类似静态代理)，而invoke函数实现中调用委托类对象new OperateImpl()相应
//的 method(是不是有点类似静态代理)。
//
//public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
//loader表示类加载器
//interfaces表示委托类的接口，生成代理类时需要实现这些接口
//h是InvocationHandler实现类对象，负责连接代理类和委托类的中间类
//
//
// 
//我们可以这样理解，如上的动态代理实现实际是双层的静态代理，开发者提供了委托类 B，程序动态生成了代理类 A。开发者还需要提供一个实现
//了InvocationHandler的子类 C，子类 C 连接代理类 A 和委托类 B，它是代理类 A 的委托类，委托类 B 的代理类。用户直接调用代理
//类 A 的对象，A 将调用转发给委托类 C，委托类 C 再将调用转发给它的委托类 B。
//
//3. 动态代理原理
//实际上面最后一段已经说清了动态代理的真正原理。我们来仔细分析下
//
//3.1 生成的动态代理类代码
//下面是上面示例程序运行时自动生成的动态代理类代码，如何得到这些生成的代码请见ProxyUtils，查看 class 文件可使用 jd-gui
//
//import com.codekk.java.test.dynamicproxy.Operate;
//import java.lang.reflect.InvocationHandler;
//import java.lang.reflect.Method;
//import java.lang.reflect.Proxy;
//import java.lang.reflect.UndeclaredThrowableException;
//
//public final class $Proxy0 extends Proxy
//  implements Operate
//{
//  private static Method m4;
//  private static Method m1;
//  private static Method m5;
//  private static Method m0;
//  private static Method m3;
//  private static Method m2;
//
//  public $Proxy0(InvocationHandler paramInvocationHandler)
//    throws 
//  {
//    super(paramInvocationHandler);
//  }
//
//  public final void operateMethod1()
//    throws 
//  {
//    try
//    {
//      h.invoke(this, m4, null);
//      return;
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  public final boolean equals(Object paramObject)
//    throws 
//  {
//    try
//    {
//      return ((Boolean)h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  public final void operateMethod2()
//    throws 
//  {
//    try
//    {
//      h.invoke(this, m5, null);
//      return;
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  public final int hashCode()
//    throws 
//  {
//    try
//    {
//      return ((Integer)h.invoke(this, m0, null)).intValue();
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  public final void operateMethod3()
//    throws 
//  {
//    try
//    {
//      h.invoke(this, m3, null);
//      return;
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  public final String toString()
//    throws 
//  {
//    try
//    {
//      return (String)h.invoke(this, m2, null);
//    }
//    catch (Error|RuntimeException localError)
//    {
//      throw localError;
//    }
//    catch (Throwable localThrowable)
//    {
//      throw new UndeclaredThrowableException(localThrowable);
//    }
//  }
//
//  static
//  {
//    try
//    {
//      m4 = Class.forName("com.codekk.java.test.dynamicproxy.Operate").getMethod("operateMethod1", new Class[0]);
//      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
//      m5 = Class.forName("com.codekk.java.test.dynamicproxy.Operate").getMethod("operateMethod2", new Class[0]);
//      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
//      m3 = Class.forName("com.codekk.java.test.dynamicproxy.Operate").getMethod("operateMethod3", new Class[0]);
//      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
//      return;
//    }
//    catch (NoSuchMethodException localNoSuchMethodException)
//    {
//      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
//    }
//    catch (ClassNotFoundException localClassNotFoundException)
//    {
//      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
//    }
//  }
//}
//
// 
//从中我们可以看出动态生成的代理类是以$Proxy为类名前缀，继承自Proxy，并且实现了Proxy.newProxyInstance(…)第二个参数传入的所有接口的类。
//如果代理类实现的接口中存在非 public 接口，则其包名为该接口的包名，否则为com.sun.proxy。
//其中的operateMethod1()、operateMethod2()、operateMethod3()函数都是直接交给h去处理，h在父类Proxy中定义为
//
//protected InvocationHandler h;
//即为Proxy.newProxyInstance(…)第三个参数。
//所以InvocationHandler的子类 C 连接代理类 A 和委托类 B，它是代理类 A 的委托类，委托类 B 的代理类。
//
//3.2. 生成动态代理类原理
//以下针对 Java 1.6 源码进行分析，动态代理类是在调用Proxy.newProxyInstance(…)函数时生成的。
//
//(1). newProxyInstance(…)
//函数代码如下：
//
//public static Object newProxyInstance(ClassLoader loader,
//                                      Class<?>[] interfaces,
//                                      InvocationHandler h)
//    throws IllegalArgumentException
//{
//    if (h == null) {
//        throw new NullPointerException();
//    }
//
//    /*
//     * Look up or generate the designated proxy class.
//     */
//    Class cl = getProxyClass(loader, interfaces);
//
//    /*
//     * Invoke its constructor with the designated invocation handler.
//     */
//    try {
//        Constructor cons = cl.getConstructor(constructorParams);
//        return (Object) cons.newInstance(new Object[] { h });
//    } catch (NoSuchMethodException e) {
//        throw new InternalError(e.toString());
//    } catch (IllegalAccessException e) {
//        throw new InternalError(e.toString());
//    } catch (InstantiationException e) {
//        throw new InternalError(e.toString());
//    } catch (InvocationTargetException e) {
//        throw new InternalError(e.toString());
//    }
//}
//从中可以看出它先调用getProxyClass(loader, interfaces)得到动态代理类，然后将InvocationHandler作为代理类构造函数入参新建代理类对象。
//
//(2). getProxyClass(…)
//函数代码及解释如下(省略了原英文注释)：
//
///**
// * 得到代理类，不存在则动态生成
// * @param loader 代理类所属 ClassLoader
// * @param interfaces 代理类需要实现的接口
// * @return
// */
//public static Class<?> getProxyClass(ClassLoader loader,
//                                     Class<?>... interfaces)
//    throws IllegalArgumentException
//{
//    if (interfaces.length > 65535) {
//        throw new IllegalArgumentException("interface limit exceeded");
//    }
//    // 代理类类对象
//    Class proxyClass = null;
//
//    /* collect interface names to use as key for proxy class cache */
//    String[] interfaceNames = new String[interfaces.length];
//
//    Set interfaceSet = new HashSet();       // for detecting duplicates
//
//    /**
//     * 入参 interfaces 检验，包含三部分
//     * （1）是否在入参指定的 ClassLoader 内
//     * （2）是否是 Interface
//     * （3）interfaces 中是否有重复
//     */
//    for (int i = 0; i < interfaces.length; i++) {
//        String interfaceName = interfaces[i].getName();
//        Class interfaceClass = null;
//        try {
//            interfaceClass = Class.forName(interfaceName, false, loader);
//        } catch (ClassNotFoundException e) {
//        }
//        if (interfaceClass != interfaces[i]) {
//            throw new IllegalArgumentException(
//                interfaces[i] + " is not visible from class loader");
//        }
//
//        if (!interfaceClass.isInterface()) {
//            throw new IllegalArgumentException(
//                interfaceClass.getName() + " is not an interface");
//        }
//
//        if (interfaceSet.contains(interfaceClass)) {
//            throw new IllegalArgumentException(
//                "repeated interface: " + interfaceClass.getName());
//        }
//        interfaceSet.add(interfaceClass);
//
//        interfaceNames[i] = interfaceName;
//    }
//
//    // 以接口名对应的 List 作为缓存的 key
//    Object key = Arrays.asList(interfaceNames);
//
//    /*
//     * loaderToCache 是个双层的 Map
//     * 第一层 key 为 ClassLoader，第二层 key 为 上面的 List，value 为代理类的弱引用
//     */
//    Map cache;
//    synchronized (loaderToCache) {
//        cache = (Map) loaderToCache.get(loader);
//        if (cache == null) {
//            cache = new HashMap();
//            loaderToCache.put(loader, cache);
//        }
//    }
//
//    /*
//     * 以上面的接口名对应的 List 为 key 查找代理类，如果结果为：
//     * (1) 弱引用，表示代理类已经在缓存中
//     * (2) pendingGenerationMarker 对象，表示代理类正在生成中，等待生成完成通知。
//     * (3) null 表示不在缓存中且没有开始生成，添加标记到缓存中，继续生成代理类
//     */
//    synchronized (cache) {
//        do {
//            Object value = cache.get(key);
//            if (value instanceof Reference) {
//                proxyClass = (Class) ((Reference) value).get();
//            }
//            if (proxyClass != null) {
//                // proxy class already generated: return it
//                return proxyClass;
//            } else if (value == pendingGenerationMarker) {
//                // proxy class being generated: wait for it
//                try {
//                    cache.wait();
//                } catch (InterruptedException e) {
//                }
//                continue;
//            } else {
//                cache.put(key, pendingGenerationMarker);
//                break;
//            }
//        } while (true);
//    }
//
//    try {
//        String proxyPkg = null;     // package to define proxy class in
//
//        /*
//         * 如果 interfaces 中存在非 public 的接口，则所有非 public 接口必须在同一包下面，后续生成的代理类也会在该包下面
//         */
//        for (int i = 0; i < interfaces.length; i++) {
//            int flags = interfaces[i].getModifiers();
//            if (!Modifier.isPublic(flags)) {
//                String name = interfaces[i].getName();
//                int n = name.lastIndexOf('.');
//                String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
//                if (proxyPkg == null) {
//                    proxyPkg = pkg;
//                } else if (!pkg.equals(proxyPkg)) {
//                    throw new IllegalArgumentException(
//                        "non-public interfaces from different packages");
//                }
//            }
//        }
//
//        if (proxyPkg == null) {     // if no non-public proxy interfaces,
//            proxyPkg = "";          // use the unnamed package
//        }
//
//        {
//            // 得到代理类的类名，jdk 1.6 版本中缺少对这个生成类已经存在的处理。
//            long num;
//            synchronized (nextUniqueNumberLock) {
//                num = nextUniqueNumber++;
//            }
//            String proxyName = proxyPkg + proxyClassNamePrefix + num;
//
//            // 动态生成代理类的字节码
//            // 最终调用 sun.misc.ProxyGenerator.generateClassFile() 得到代理类相关信息写入 DataOutputStream 实现
//            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
//                proxyName, interfaces);
//            try {
//                // native 层实现，虚拟机加载代理类并返回其类对象
//                proxyClass = defineClass0(loader, proxyName,
//                    proxyClassFile, 0, proxyClassFile.length);
//            } catch (ClassFormatError e) {
//                throw new IllegalArgumentException(e.toString());
//            }
//        }
//        // add to set of all generated proxy classes, for isProxyClass
//        proxyClasses.put(proxyClass, null);
//
//    } finally {
//        // 代理类生成成功则保存到缓存，否则从缓存中删除，然后通知等待的调用
//        synchronized (cache) {
//            if (proxyClass != null) {
//                cache.put(key, new WeakReference(proxyClass));
//            } else {
//                cache.remove(key);
//            }
//            cache.notifyAll();
//        }
//    }
//    return proxyClass;
//}
//函数主要包括三部分：
//
//入参 interfaces 检验，包含是否在入参指定的 ClassLoader 内、是否是 Interface、interfaces 中是否有重复
//以接口名对应的 List 为 key 查找代理类，如果结果为：
//弱引用，表示代理类已经在缓存中；
//pendingGenerationMarker 对象，表示代理类正在生成中，等待生成完成返回；
//null 表示不在缓存中且没有开始生成，添加标记到缓存中，继续生成代理类。
//如果代理类不存在调用ProxyGenerator.generateProxyClass(…)生成代理类并存入缓存，通知在等待的缓存。
//函数中几个注意的地方：
//
//代理类的缓存 key 为接口名对应的 List，接口顺序不同表示不同的 key 即不同的代理类。
//如果 interfaces 中存在非 public 的接口，则所有非 public 接口必须在同一包下面，后续生成的代理类也会在该包下面。
//代理类如果在 ClassLoader 中已经存在的情况没有做处理。
//可以开启 System Properties 的sun.misc.ProxyGenerator.saveGeneratedFiles开关，保存动态类到目的地址。
//Java 1.7 的实现略有不同，通过getProxyClass0(…)函数实现，实现中调用代理类的缓存，判断代理类在缓存中是否已经存在，存在直接返回，不存在则调用proxyClassCache的valueFactory属性进行动态生成，valueFactory的apply函数与上面的getProxyClass(…)函数逻辑类似。
//
//4. 使用场景
//4.1 J2EE Web 开发中 Spring 的 AOP(面向切面编程) 特性
//作用：目标函数之间解耦。
//比如在 Dao 中，每次数据库操作都需要开启事务，而且在操作的时候需要关注权限。一般写法是在 Dao 的每个函数中添加相应逻辑，造成代码冗余，耦合度高。
//使用动态代理前伪代码如下：
//
//Dao {
//    insert() {
//        判断是否有保存的权限；
//        开启事务；
//        插入；
//        提交事务；
//    }
//
//    delete() {
//        判断是否有删除的权限；
//        开启事务；
//        删除；
//        提交事务；
//    }
//}
//使用动态代理的伪代码如下：
//
//// 使用动态代理，组合每个切面的函数，而每个切面只需要关注自己的逻辑就行，达到减少代码，松耦合的效果
//invoke(Object proxy, Method method, Object[] args)
//                    throws Throwable {
//    判断是否有权限；
//    开启事务；
//    Object ob = method.invoke(dao, args)；
//    提交事务；
//    return ob; 
//}
//4.2 基于 REST 的 Android 端网络请求框架 Retrofit
//作用：简化网络请求操作。
//一般情况下每个网络请求我们都需要调用一次HttpURLConnection或者HttpClient进行请求，或者像 Volley 一样丢进等待队列中，Retrofit 极大程度简化了这些操作，示例代码如下：
//
//public interface GitHubService {
//  @GET("/users/{user}/repos")
//  List<Repo> listRepos(@Path("user") String user);
//}
//
//RestAdapter restAdapter = new RestAdapter.Builder()
//    .setEndpoint("https://api.github.com")
//    .build();
//
//GitHubService service = restAdapter.create(GitHubService.class);
//以后我们只需要直接调用
//
//List<Repo> repos = service.listRepos("octocat");
//即可开始网络请求，Retrofit的原理就是基于动态代理，它同时用到了 注解 的原理，本文不做深入介绍，具体请等待 Retrofit 源码解析 完成。

